﻿using System.Collections.Generic;
using System.Linq;
using Summer.IO;
using FastReflectionLib;

#region License
/*
 *  Copyright (c) Dumuzi.cn 2009 , All rights reserved.
 *  CLR Version: 2.0.50727.4927
 *  NameSpace: Summer.Core.Ioc
 *  Author:Edwin Tai,戴佳顺
 *  Msn:edwin19861218@hotmail.com
 *  QQ: 1961218
 *  Date:2009-11-24 15:38:24
 *  Licensed under the Microsoft Public License (Ms-PL)
 *  This license governs use of the accompanying software. 
 *  If you use the software, you accept this license.
 *  If you do not accept the license, do not use the software.
 */
#endregion

namespace Summer.Core.Ioc
{
    /// <summary>
    /// Context intialization
    /// </summary>
    public static class ContextManager
    {
        /// <summary>
        /// Find the contextObject by it's name in some context
        /// </summary>
        /// <param name="context"></param>
        /// <param name="strRef"></param>
        /// <returns></returns>
        public static IContextObject FindContextObjectByRef(Context context, string strRef)
        {
            foreach (IContextObject o in context.Values)
            {
                if (o.Name == strRef)
                {
                    if (o.Ref == null || o.Ref.Trim() == string.Empty)
                    {
                        return o;
                    }
                    return FindContextObjectByRef(context, o.Ref);
                }

            }
            return null;
        }
        /// <summary>
        /// Initialize the context and set it's ContextObject and Properities
        /// </summary>
        /// <param name="contextObj"></param>
        /// <param name="context"></param>
        public static void SetObjectInContextObject(IContextObject contextObj, Context context)
        {
            if (contextObj.Ref != null && contextObj.Ref.Trim() != string.Empty)
            {
                //Has ref
                IContextObject obj1 = FindContextObjectByRef(context, contextObj.Ref);//Find the ref related object
                if (obj1 == null)
                {
                    throw new Summer.Exception.IocException("Cannot find the ContextObject by Ref string", typeof(ContextManager));
                }
                contextObj.Ref = null;
                contextObj.Class = obj1.Class;
                contextObj.Property = obj1.Property;
                contextObj.Singleton = obj1.Singleton;
            }
            if (contextObj.Class == null || contextObj.Class.Trim() == string.Empty)
            {
                //Page or mvc
                return;
            }
            if (contextObj.Singleton && contextObj.Object != null)
            {
                //Singleton and has initialized
                return;
            }
            object instance = contextObj.Class.LoadLibrary();
            if (contextObj.Property != null && contextObj.Property.Count() != 0)
            {
                SetPropertyInContextObject(contextObj, context, instance);   
            }
            contextObj.Object = instance;

        }
        /// <summary>
        /// Set the property of ContextObject
        /// </summary>
        /// <param name="contextObj"></param>
        /// <param name="context"></param>
        /// <param name="instance"></param>
        public static void SetPropertyInContextObject(IContextObject contextObj,Context context,object instance)
        {
            foreach (var pro in contextObj.Property)
            {
                object nameList = pro.ObjectName;
                object propertySetter = null;
                if (nameList.GetType() == typeof(string))
                {
                    IContextObject obj = FindContextObjectByRef(context, nameList.ToString());
                    if (obj == null)
                    {
                        throw new Summer.Exception.IocException("Cannot find the ContextObject by its name string", typeof(ContextManager));
                    }
                    SetObjectInContextObject(obj, context);
                    propertySetter = obj.Object;
                }
                else if (nameList.GetType() == typeof(List<string>))
                {
                    //List<string>
                    //TODO
                }
                else if (nameList.GetType() == typeof(Dictionary<string, string>))
                {
                    //Dictionary<string,sring>
                    //TODO
                }
                else
                {
                    throw new Summer.Exception.IocException("The type cannot be initlized in property", typeof(ContextManager));
                }
                instance.GetType().GetMethod("set_".ToStringJoiner() + pro.Name).FastInvoke(instance, propertySetter);
            }
        }
    }
}
